/**
 * Copyright (c) Daniel Centore
 *
 * ex: set filetype=java expandtab tabstop=4 shiftwidth=4 :
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation.
 */
package ronp.anim.undo;

import java.util.Stack;

import ronp.anim.data.filmstrip.Animation;

/**
 * Controls undos asnd redos in the game.
 * Works by copying the whole {@link Animation} each time.
 * Inefficient, but easy to implement and maintain.
 * 
 * @author Daniel Centore
 *
 */
public class UndoController
{
	public static final int MAXIMUM_UNDO_HISTORY = 20; // How many moves to store in memory

	private Stack<Animation> undoStack;
	private Stack<Animation> redoStack;
	private final Animation animation;

	/**
	 * Creates an {@link UndoController}
	 * @param anim The {@link Animation} to link it to
	 */
	public UndoController(Animation anim)
	{
		undoStack = new Stack<Animation>();
		redoStack = new Stack<Animation>();

		animation = anim;

		addMove();
	}

	/**
	 * Call this method BEFORE applying the change
	 */
	public void addMove()
	{
		redoStack.clear();
		undoStack.push(new DeepCopy<Animation>().copy(animation));

		if (undoStack.size() > MAXIMUM_UNDO_HISTORY)
			undoStack.remove(0);
	}

	/**
	 * Undoes a previous move (or does nothing if no more moves remain)
	 * @return True if the move was applied; False otherwise
	 */
	public boolean undo()
	{
		if (undoStack.isEmpty())
			return false;

		Animation move = undoStack.pop();
		redoStack.push(new DeepCopy<Animation>().copy(animation));

		animation.applyUndo(move);

		animation.repaint();

		return true;
	}

	/**
	 * Redoes a move (or does nothing if no more moves remain)
	 * @return True if the move was applied; False otherwise
	 */
	public boolean redo()
	{
		if (redoStack.isEmpty())
			return false;

		Animation move = redoStack.pop();
		undoStack.push(new DeepCopy<Animation>().copy(animation));
		animation.applyUndo(move);

		animation.repaint();

		return true;
	}

}
